import {
    getPixels,
    convertImageToBitmap
} from './get-Image-pixels'
import bleDisNetwork from './bleDisNetwork';
import lzo from './lzo'

const encoding = require('./encoding.js')

const GRAY_THRESHOLD = 200; // 灰度阈值
let mtuVal = 20 // 每次发送的最大数据包大小
function cCException(str) {
    //字符串转gb2312
    return new encoding.TextEncoder("gb2312", {
        NONSTANDARD_allowLegacyEncoding: true
    }).encode(str).buffer
}

/*文字*/
async function textPrint(str) {
    // 移动打印位置
    if (!await advancePositionMethod(0)) {
        console.log('textPrint 退出');
        return false;
    }
    let buffer = cCException(str)
    for (var j = 0; j < buffer.byteLength; j += 20) {
        bleDisNetwork.writeBluetoothCharacteristicValue(buffer.slice(j, j + 20))
    }
    backPaper()
    return true;
}
/**
 * 打印一维码(code128)
 * @param {number} byWidth - 条形码宽度，byWidth∈[2,5]
 * @param {number} byHeight - 条形码高度，byHeight∈[1,9]
 * @param {boolean} byHumanRead - 是否打印人工识别字符
 * @param {string} data - 条形码数据，1 ≤ 数据长度 ≤ 232 字节
 * @returns {Promise<boolean>} - 发送成功返回 true，否则 false
 */
async function printCode128(byWidth, byHeight, byHumanRead, data) {
    // 移动打印位置
    if (!await advancePositionMethod(0)) {
        console.log('打印条码 退出');
        return false;
    }
    // 参数校验
    if (byWidth < 2 || byWidth > 5 || byHeight < 1 || byHeight > 9 || !data || data.length === 0) {
        return false;
    }
    if (data.length > 232 || data.length < 1) {
        return false;
    }

    // 人工识别字符标志
    const humanRead = byHumanRead ? 0x03 : 0x01;

    // 判断是否纯数字且长度为偶数
    const isNumeric = /^\d+$/.test(data);
    const startcode = (isNumeric && data.length % 2 === 0) ? 0x8A : 0x89;

    // 数据转字节数组
    const bytes = cCException(data);
    const len = bytes.byteLength;

    // 发送指令头
    const senddata = new Uint8Array([
        0x1C, 0x50, 0x08,
        byWidth,
        byHeight,
        humanRead,
        len + 1,
        startcode
    ]);
    console.log('条形码数据:', data, 'startcode:', bytes);
    // 发送指令头和数据
    const res1 = await PrintSend(senddata);
    if (!res1) return false;
    const res2 = await PrintSend(bytes);
    backPaper()
    return res2;
}

// 压缩和解压缩文本数据
function compressData(originalData) {
    let params = {
        inputBuffer: originalData,
        outputBuffer: null
    }
    lzo.compress(params);
    return params.outputBuffer
}

// 解压缩函数
function decompressData(compressedData) {
    let params = {
        inputBuffer: compressedData,
        outputBuffer: null
    }
    lzo.decompress(params);
    return params.outputBuffer
}

/**
 * 打印位图
 * @param {string} imagePath - 位图path
 * @param {number} xP - x坐标位置
 * @param {number} yP - y坐标位置
 * @returns {Promise<boolean>} 打印结果
 */
async function printBitmap(imagePath, xP, yP) {
    console.log(`printBitmap 参数 xP:${xP} yp:${yP}`);

    // 移动打印位置
    if (!await advancePositionMethod(yP)) {
        console.log('printBitmap 退出');
        return false;
    }
    const bitmap = await convertImageToBitmap(imagePath)
    const bWidth = bitmap.width;
    const bHeight = bitmap.height;
    const data = new Uint8Array(bWidth * 3); // 打印机最小单次可接受打印的数据
    const cmd = new Uint8Array([0x1b, 0x2a, 0x27, bWidth & 0xff, (bWidth >> 8) & 0xff]);
    const lzoCmdHead = new Uint8Array([0x10, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00]);
    const feedLine = new Uint8Array([0x0d, 0x1b, 0x4a, 0x18]);
    let pixels = new Uint32Array(bWidth * 24);

    // 计算图片分段
    const remaining = bHeight % 24;
    const bH = bHeight - remaining;
    const firstH = bHeight + (remaining > 0 ? (24 - remaining) : 0);
    const last = remaining === 0 ? firstH : firstH - 24;

    let isPrintData = false;
    let gOneElement = 0; // 跳行计数
    let platform = await bleDisNetwork.getSystemInfo();
    if (platform === 'ios') {
        mtuVal = await bleDisNetwork.getBLEMTU()
    } else {
        // 安卓默认mtu 20
        mtuVal = 20
    }
    // 分段处理图片数据
    for (let y = 0; y < firstH; y += 24) {
        let isPrint = false;

        if (y >= bH) {
            // 处理剩余数据
            pixels.fill(0xFFFFFF, remaining * bWidth, pixels.length);
            pixels = await getPixels(0, y, bWidth, remaining);
        } else {
            pixels = await getPixels(0, y, bWidth, 24);
        }
        // 检查是否需要打印
        for (let i = 0; i < pixels.length; i++) {
            if ((pixels[i] & 0xFFFFFF) < 0xFFFFFF) {
                isPrint = true;
                break;
            }

            if (i === pixels.length - 1 && !isPrint) {
                gOneElement++;
            }
        }

        if (isPrint) {
            if (gOneElement > 0) {
                // 跳行处理
                await DSAdvancePosition(gOneElement * 0.133);
                if (isPrintData) {
                    await sendEqual(new Uint8Array([0x0d]), 1);
                }
            }

            gOneElement = 0;
            // 转换像素数据
            for (let b = 0, index = 0; b < bWidth; b++) {
                data[index++] = compressColor(pixels, b, bWidth);
                data[index++] = compressColor(pixels, b + bWidth * 8, bWidth);
                data[index++] = compressColor(pixels, b + bWidth * 16, bWidth);
            }

            await setHP(xP);

            let wid = bWidth / 8;
            //位图 宽 高
            let hei = bHeight / wid; //每一份数据高度 (最大不超24.数据总量 除 每行字节数 得到 高度)
            //头四位 位图宽高
            const comHead = [
                wid & 0xff,
                (wid >> 8) & 0xff,
                hei & 0xff,
                (hei >> 8) & 0xff
            ];
            let comHeadData = new Uint8Array(comHead);
            let originalData = appendUint8Arrays(comHeadData, data);
            let toPrintData = compressData(originalData);
            const compress_len = toPrintData.length
            lzoCmdHead[3] = compress_len & 0xff;
            lzoCmdHead[4] = (compress_len >> 8) & 0xff;
            lzoCmdHead[5] = (compress_len >> 16) & 0xff;
            lzoCmdHead[6] = (compress_len >> 24) & 0xff;
            console.log(`压缩数据长度：${compress_len}`, toPrintData);
            const cmdResult = await PrintSend(lzoCmdHead);
            console.log(`打印head指令 结果：${cmdResult}`);
            const dataResult = await PrintSend(toPrintData);
            console.log(`打印图片数据 结果：${dataResult}`);
            if (y === last) {
                feedLine[3] = remaining;
            }
            const feedLineResult = await PrintSend(feedLine);
            console.log(`换行打印 结果：${feedLineResult}`);
        }
    }

    // 最后进纸处理
    if (gOneElement > 0) {
        await DSAdvancePosition(gOneElement * 0.133);
    }
    const result = await setHP(0); // 打印头归位
    console.log(`printBitmap 退出 发送结果:${result}`);
    backPaper()
    return result;
}

function appendUint8Arrays(a, b) {
    const result = new Uint8Array(a.length + b.length);
    result.set(a, 0); // Copy 'a' into the start of 'result'
    result.set(b, a.length); // Copy 'b' after 'a' in 'result'
    return result;
}
/**
 * 检测图片有效内容边界
 * @param {*} bitmap - 位图对象
 * @returns {Object|null} 返回边界对象 {top, bottom, left, right} 或 null
 */
async function detectImageBounds(bitmap) {
    const width = bitmap.width;
    const height = bitmap.height;
    let top = -1,
        bottom = -1,
        left = width,
        right = -1;

    // 检测上边界
    for (let y = 0; y < height && top === -1; y++) {
        const pixels = await getPixels(0, y, width, 1);
        for (let x = 0; x < width; x++) {
            if (isPrintPoint(pixels[x])) {
                top = y;
                break;
            }
        }
    }

    // 如果没有找到内容，返回null
    if (top === -1) return null;

    // 检测下边界
    for (let y = height - 1; y >= top && bottom === -1; y--) {
        const pixels = await getPixels(0, y, width, 1);
        for (let x = 0; x < width; x++) {
            if (isPrintPoint(pixels[x])) {
                bottom = y;
                break;
            }
        }
    }

    // 检测左右边界
    for (let y = top; y <= bottom; y++) {
        const pixels = await getPixels(0, y, width, 1);
        for (let x = 0; x < width; x++) {
            if (isPrintPoint(pixels[x])) {
                left = Math.min(left, x);
                right = Math.max(right, x);
            }
        }
    }

    // 确保边界有效
    if (left > right) return null;

    return {
        top,
        bottom,
        left,
        right
    };
}

/**
 * 检查一行是否有有效内容
 * @param {Uint32Array} pixels - 像素数据
 * @param {number} width - 图片宽度  
 * @param {number} row - 行号
 * @returns {boolean} 是否有内容
 */
function hasContentInRow(pixels, width, row) {
    const startIndex = row * width;
    const endIndex = startIndex + width;

    for (let i = startIndex; i < endIndex; i++) {
        if (i < pixels.length && isPrintPoint(pixels[i])) {
            return true;
        }
    }
    return false;
}

function backPaper() {
    // 发送退纸指令
    const backBytes = new Uint8Array([0x0c]);
    sendEqual(backBytes, 1);
}
/**
 * 压缩颜色数据
 * @param {Uint32Array} pixels - 像素数据
 * @param {number} start - 起始位置
 * @param {number} stride - 步长
 * @returns {number} 压缩后的数据
 */
function compressColor(pixels, start, stride) {
    let ret = 0;
    for (let i = 7; i >= 0; i--, start += stride) {
        if (start >= pixels.length) {
            console.log("ESCP", "over");
            break; // 或 return ret;
        }
        ret |= isPrintPoint(pixels[start]) << i;
    }
    return ret;
}
/**
 * 顺向走纸
 * @param {number} inch - 走纸距离，单位英寸
 * @returns {boolean}
 */
async function DSAdvancePosition(inch) {
    // 1英寸=180dot
    let temp = Math.floor(inch * 180);

    // 先发多次 0x1b 0x4a 0xff
    while (temp > 255) {
        temp -= 255;
        const bytes = new Uint8Array([0x1b, 0x4a, 0xff]);
        const ret = await sendEqual(bytes, 3);
        if (!ret) return false;
    }

    // 剩余部分
    const len = temp & 0xFF;
    const cmd_send = new Uint8Array([0x1b, 0x4a, len]);
    const is = await sendEqual(cmd_send, 3);
    return is;
}
/**
 * 判断是否打印点
 * @param {number} color - 颜色值
 * @returns {number} 是否打印
 */
function isPrintPoint(color) {
    const red = (color & 0xff0000) >> 16;
    const green = (color & 0xff00) >> 8;
    const blue = color & 0xff;
    const gray = Math.floor(red * 0.30 + green * 0.59 + blue * 0.11);
    return gray < GRAY_THRESHOLD ? 1 : 0;
}

/**
 * 顺向走纸
 * @param {number} temp - 走纸距离(dot)
 * @returns {Promise<boolean>} 发送结果
 */
async function advancePositionMethod(temp) {
    console.log(`advancePositionMethod 参数 temp${temp}`);
    const bytes = new Uint8Array([27, 74, 0xff]);

    if (temp > 255) {
        for (let i = 0; i < Math.floor(temp / 255); i++) {
            const result = await sendEqual(bytes, bytes.length);
            if (!result) {
                console.log(`advancePositionMethod 退出 发送结果:${result}`);
                return false;
            }
        }
    }

    const bytes2 = new Uint8Array([27, 74, temp & 0xFF]);
    if (bytes2[2] === 0) {
        console.log('advancePositionMethod 退出');
        return true;
    }

    const result = await sendEqual(bytes2, bytes2.length);
    console.log(`advancePositionMethod 退出 发送结果:${result}`);
    return result;
}

/**
 * 通过蓝牙发送数据到打印机
 * @param {Uint8Array} bytes - 要发送的字节数据
 * @param {number} length - 实际发送长度（通常等于 bytes.length）
 * @returns {Promise<boolean>} - 发送成功返回 true，否则 false
 */
function sendEqual(bytes, length) {
    return new Promise(async (resolve, reject) => {
        console.log('sendEqual======', bytes, length)
        try {
            await bleDisNetwork.writeBluetoothCharacteristicValue(bytes.buffer.slice(0, length))
            resolve(true);
        } catch (error) {
            console.error('蓝牙发送失败', error);
            resolve(false);
        }
    });
}
/**
 * 设置水平打印位置
 * @param {number} position - 单位/dot
 * @returns {Promise<boolean>}
 */
async function setHP(position) {
    if (position <= 2448) {
        return setAHP(position);
    } else {
        const temp = position - 2448;
        const res1 = await setAHP(2448);
        if (!res1) return false;
        return setRHP(temp);
    }
}

function setRHP(position) {
    const bytes = new Uint8Array([0x1b, 0x5c, position & 0xff, (position >> 8) & 0xff]);
    return sendEqual(bytes, 4);
}

function setAHP(position) {
    // 指令精度 1/60 inch，默认 dpi:180，所以➗3进行换算。
    const temp = Math.floor(position / 3);
    const bytes = new Uint8Array([0x1b, 0x24, temp & 0xff, (temp >> 8) & 0xff]);
    // 只要不是0就发
    if (bytes[2] === 0) return Promise.resolve(true);
    return sendEqual(bytes, 4);
}

/**
 * 打印数据发送（自动分包，适配微信小程序蓝牙）
 * @param {Uint8Array} bytes - 要发送的字节数据
 * @returns {Promise<boolean>} - 全部包都发送成功返回 true，否则 false
 */
async function PrintSend(bytes) {
    const MAX_PACKET = mtuVal; // 每次发送的最大数据包大小
    const totalLen = bytes.length || bytes.byteLength;
    let offset = 0;
    console.log('PrintSend======', bytes.length, bytes.byteLength);

    while (offset < totalLen) {
        const end = Math.min(offset + MAX_PACKET, totalLen);
        const packet = bytes.slice(offset, end);
        console.log('PrintSend 发送数据:', 'offset:', offset, 'end:', end, 'mtuVal:', mtuVal);
        // 兼容 Uint8Array/ArrayBuffer
        let dataBuffer = packet instanceof Uint8Array ? packet.buffer : packet;
        try {
            let res = await bleDisNetwork.writeBluetoothCharacteristicValue(dataBuffer);
            console.log('sendNext 发送结果:', res);
            offset = end;
        } catch (error) {
            console.error('蓝牙发送失败', error);
            return false;
        }
    }
    return true;
}

// 转十六进制字符串
function ab2hex(buffer) {
    const hexArr = Array.prototype.map.call(
        new Uint8Array(buffer),
        function (bit) {
            return ('00' + bit.toString(16)).slice(-2)
        }
    )
    return hexArr.join(',')
}
// 发送获取设备名称指令
function getDeviceName() {
    const cmd = new Uint8Array([0x1D, 0x04, 0xA2]);
    sendEqual(cmd, 3)
}

// 导出模块
export default {
    textPrint,
    printCode128,
    printBitmap,
    compressColor,
    isPrintPoint,
    advancePositionMethod,
    sendEqual,
    getDeviceName
}